﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
//.NET socket libraries
using System.Net;
using System.Net.Sockets;
//for threading inclu threads safe method
using System.Threading;
using System.Net.NetworkInformation;
using System.Diagnostics;
using GlobalObjects;


namespace Drivers.Swisstom
{
    public class Swisstom0 : Swisstom, IDriver 
    {
        int IQSize;
        int IQ2Size;  //injection electrode voltage

        SimpleDataEvent OnSimpleData;
        RawDataEvent OnRawData;
        MessageEvent OnMessage;
        ConnectedEvent OnConnected;

        int code;

        bool FireEventsDataMsg;

        public Swisstom0()
        {
            DataPort = new Ethernet();
            MsgPort = new Ethernet();
            ApplyDefaultPort();
            PreviousDeviceIP = "";
            Connected = false;
            code = 0;
            FireEventsDataMsg = true;
        }

        #region EventImplementation

        event SimpleDataEvent IDriver.OnSimpleData
        {
            add
            {
                if (OnSimpleData != null)
                {
                    lock (OnSimpleData)
                    {
                        OnSimpleData += value;
                    }
                }
                else
                {
                    OnSimpleData = new SimpleDataEvent(value);
                }
            }
            remove
            {
                if (OnSimpleData != null)
                {
                    lock (OnSimpleData)
                    {
                        OnSimpleData -= value;
                    }
                }
            }
        }
        event RawDataEvent IDriver.OnRawData
        {
            add
            {
                if (OnRawData != null)
                {
                    lock (OnRawData)
                    {
                        OnRawData += value;
                    }
                }
                else
                {
                    OnRawData = new RawDataEvent(value);
                }
            }
            remove
            {
                if (OnRawData != null)
                {
                    lock (OnRawData)
                    {
                        OnRawData -= value;
                    }
                }
            }
        }
        event MessageEvent IDriver.OnMessage
        {
            add
            {
                if (OnMessage != null)
                {
                    lock (OnMessage)
                    {
                        OnMessage += value;
                    }
                }
                else
                {
                    OnMessage = new MessageEvent(value);
                }
            }
            remove
            {
                if (OnMessage != null)
                {
                    lock (OnMessage)
                    {
                        OnMessage -= value;
                    }
                }
            }
        }
        event ConnectedEvent IDriver.OnConnected
        {
            add
            {
                if (OnConnected != null)
                {
                    lock (OnConnected)
                    {
                        OnConnected += value;
                    }
                }
                else
                {
                    OnConnected = new ConnectedEvent(value);
                }
            }
            remove
            {
                if (OnConnected != null)
                {
                    lock (OnConnected)
                    {
                        OnConnected -= value;
                    }
                }
            }
        }

        #endregion

        #region port10000
        private void MsgPort_OnReceived(Object sender, EventArgs e)
        {
            if (FireEventsDataMsg)
            {
                System.Text.Encoding enc = System.Text.Encoding.ASCII;
                byte[] LocalBuffer = MsgPort.DataByte.ToArray();
                MsgPort.DataByte.RemoveRange(0, LocalBuffer.Length);

                string myString = enc.GetString(LocalBuffer);
                //Debug.WriteLine(myString);

                EventArgsMsg arg = new EventArgsMsg("Swisstom0, port:10000", myString);
                if (OnMessage != null)
                    OnMessage(null, arg);
            }
        }

        #endregion

        #region port10001

        private void DataPort_OnReceived(Object sender, EventArgs e)
        {
            if (FireEventsDataMsg)
            {
                code = GetCodeFromDataPacket();
                FillsSizeFromDataPacket();
                switch (code)
                {
                    case 0:
                        //all Data
                        if (DataPort.DataByte.Count >= DataSize)
                        {
                            int DataPacketToRetrieve = (int)(DataPort.DataByte.Count / DataSize);
                            for (int i = 0; i < DataPacketToRetrieve; i++)
                            {
                                SimpleData sd = PopSimpleData();
                                EventArgsSimpleData arg = new EventArgsSimpleData(sd);

                                if (OnSimpleData != null)
                                    OnSimpleData(null, arg);
                            }
                        }
                        break;
                    case 1:
                        //all Data
                        if (DataPort.DataByte.Count >= DataSize)
                        {
                            int DataPacketToRetrieve = (int)(DataPort.DataByte.Count / DataSize);
                            for (int i = 0; i < DataPacketToRetrieve; i++)
                            {
                                RawData rd = PopRawData();
                                EventArgsRawData arg = new EventArgsRawData(rd);

                                if (OnRawData != null)
                                    OnRawData(null, arg);
                            }
                        }
                        break;
                }
            }
        }

        public int GetCodeFromDataPacket()
        {
            int output = -1;
            byte[] buffer=null;

            if (DataPort.DataByte.Count > 3)
            {
                buffer = new byte[4];
                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i];
                }
                output = BitConverter.ToInt32(buffer, 0);
            }
            return output ;
        }
        public void FillsSizeFromDataPacket()
        {
            byte[] buffer = new byte[4];

            for (int i = 0; i < 4; i++)
            {
                buffer[i] = DataPort.DataByte[i + 4 * 1];
            }
            DataSize = BitConverter.ToInt32(buffer, 0);

            for (int i = 0; i < 4; i++)
            {
                buffer[i] = DataPort.DataByte[i+4*10];
            }
            IQSize = BitConverter.ToInt32(buffer, 0);
        }
        public int GetSize()
        {
            Stop();
            Thread.Sleep(100);
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            Start(1);
            int timeout = 20;
            for (int tick = 0; tick < timeout; tick++)
            {
                Thread.Sleep(100);
                if (DataPort.DataByte.Count > 50)
                {
                    tick = timeout+1;
                }
            }

            if (DataPort.DataByte.Count > 50)
            {
                byte[] buffer = new byte[4];
                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i + 4];
                }
                DataSize = BitConverter.ToInt32(buffer, 0);

                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i + 4 * 9];
                }
                IQ2Size = BitConverter.ToInt32(buffer, 0);

                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i + 4 * 10];
                }
                IQSize = BitConverter.ToInt32(buffer, 0);
            }
            return DataSize;
        }
        public string GetDataHeader()
        {
            FireEventsDataMsg = false;
            string s = "";
            Stop();
            Thread.Sleep(100);
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            Start(1);
            Thread.Sleep(100);
            byte[] buffer = new byte[4];
            for (int j = 0; j < 12; j++)
            {
                for (int i = 0; i < 4; i++)
                {
                    buffer[i] = DataPort.DataByte[i + j * 4];
                }
                s += BitConverter.ToInt32(buffer, 0).ToString() + '\n';
            }
            FireEventsDataMsg = true;
            return s;
        }

        public string GetCode()
        {
            FireEventsDataMsg = false;
            string s = "";
            Stop();
            Thread.Sleep(200);
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            Start(1);
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(100);
                s = GetCodeFromDataPacket().ToString();
                if (s != "-1")
                {
                    i = 11;
                }
            }
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            FireEventsDataMsg = true;
            return s;
        }

        private string GetFirmwareInfo()
        {
            FireEventsDataMsg = false;
            string s = "";
            Stop();
            Thread.Sleep(100);
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            Thread.Sleep(100);
            Send("Version");
            byte[] LocalBuffer=null;
            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(100);
                System.Text.Encoding enc = System.Text.Encoding.ASCII;
                LocalBuffer = MsgPort.DataByte.ToArray();
                s = enc.GetString(LocalBuffer);
                string [] splitstring = s.Split('\n');
                int firmwareNameIndex=0;
                for (int j = 0; j < splitstring.Length; j++)
                {
                    if (splitstring[j].Contains("SBC"))
                    {
                        i = 11;
                        firmwareNameIndex = j;
                    }
                }
                s = splitstring[firmwareNameIndex];
            }
            MsgPort.DataByte.RemoveRange(0, LocalBuffer.Length);
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            FireEventsDataMsg = true;
            return s;
        }

        #endregion

        #region DataHandling

        private SimpleData PopSimpleData()
        {
            SimpleData sd = new SimpleData(IQSize/8, IQ2Size/8);
            byte[] buffer = new byte[4];

            int IQ2Pointer = 12 * 4;
            int IQPointer = IQ2Pointer + IQ2Size;

            for (int i = 0; i < (IQ2Size / 8); i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    buffer[j] = DataPort.DataByte[j + 8 * i + IQ2Pointer];
                }
                sd.I2[i] = BitConverter.ToInt32(buffer, 0);

                for (int j = 0; j < 4; j++)
                {
                    buffer[j] = DataPort.DataByte[j+4 + 8 * i + IQ2Pointer];
                }
                sd.Q2[i] = BitConverter.ToInt32(buffer, 0);
            }

            for (int i = 0; i < (IQSize / 8); i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    buffer[j] = DataPort.DataByte[j + 8 * i + IQPointer];
                }
                sd.I[i] = BitConverter.ToInt32(buffer, 0);

                for (int j = 0; j < 4; j++)
                {
                    buffer[j] = DataPort.DataByte[j+4 + 8 * i + IQPointer];
                }
                sd.Q[i] = BitConverter.ToInt32(buffer, 0);
            }
            DataPort.DataByte.RemoveRange(0, DataSize);

            return sd;
        }

        private RawData PopRawData()
        {
            int B= 2;
            int B2 = 2*B;


            RawData rd = new RawData(IQSize / B2);

            byte[] buffer = new byte[B];

            int RawPointer = 12 * 4;

            for (int i = 0; i < (IQSize / B2); i++)
            {
                for (int j = 0; j < B; j++)
                {
                    buffer[j] = DataPort.DataByte[j + B2 * i + RawPointer];
                }
                if (B == 2)
                {
                    rd.Signal1[i] = BitConverter.ToInt16(buffer, 0);
                }
                else
                {
                    //rd.Signal1[i] = BitConverter.ToInt32(buffer, 0);
                }

                for (int j = 0; j < B; j++)
                {
                    buffer[j] = DataPort.DataByte[j+B + B2 * i + RawPointer];
                }

                if (B == 2)
                {
                    rd.Signal2[i] = BitConverter.ToInt16(buffer, 0);
                }
                else
                {
                   // rd.Signal2[i] = BitConverter.ToInt32(buffer, 0);
                }
            }
            DataPort.DataByte.RemoveRange(0, DataSize);
            return rd;
        }

        #endregion

        #region Connection
        override public void ConnectP2P()
        {
            IPAddress = "192.168.1.254";
            DeviceDetected = true;
            ConnectAllPort();
        }
        override protected void ConnectAllPort()
        {
            bool ConnectionSuccessful = false;
            DataPort = new Ethernet();
            MsgPort = new Ethernet();
            //IPAddress = "138.131.49.39";
            DataPort.SetIPAddress(IPAddress);
            MsgPort.SetIPAddress(IPAddress);
            ApplyDefaultPort();

            if (DeviceDetected)
            {
                if (ConnectAPort(ref MsgPort))
                {
                    PreviousDeviceIP = IPAddress;
                    if (ConnectAPort(ref DataPort))
                    {
                        Debug.WriteLine("DEVICE is CONNECTED!");
                        ConnectionSuccessful = true;

                        GetSize();
                        Stop();
                        DataPort.ClearBuffer();
                        MsgPort.ClearBuffer();

                        Thread.Sleep(300);

                        DataPort.OnReceived += new Ethernet.OnReceivedHandler(DataPort_OnReceived);
                        MsgPort.OnReceived += new Ethernet.OnReceivedHandler(MsgPort_OnReceived);

                        if ((OnConnected != null) && ConnectionSuccessful)
                            OnConnected(null, null);
                    }
                }
            }

            
        }

        #endregion

        public void Reset()
        {
            DataPort.ClearBuffer();
            MsgPort.ClearBuffer();
            Thread.Sleep(100);
        }

        public DeviceInfo GetDeviceInfo()
        {
            DeviceInfo di = new DeviceInfo();
            di.Manufacturer = "Swisstom";
            di.ConnectionType = "ethernet";
            di.DeviceName = "Swisstom BB1";
            di.IPAddress="";
            di.Protocol = "";
            di.FirmwareVersion = "";
            if (MsgPort.IsConnected())
            {
                di.FirmwareVersion = GetFirmwareInfo();
                di.IPAddress=MsgPort.IPName.ToString();
                di.Protocol = GetCode();
            }
            return di;
        }
    }
        
}
